package cn.my.framework.common.controller;

import cn.my.framework.common.entity.Menu;
import cn.my.framework.config.shiro.MyShiroRealm;
import cn.my.framework.example.TestData;
import cn.my.framework.util.CommonUtils;
import cn.my.framework.util.ConstantData;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.subject.support.WebDelegatingSubject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by zhangl_lc on 2017/7/12.
 */
@Controller
public class CommonController {

    Logger logger = LoggerFactory.getLogger(CommonController.class);

    @Autowired
    MyShiroRealm myShiroRealm;
    @Autowired
    DefaultKaptcha captchaProducer;

    @RequestMapping(value = "/login",method = {RequestMethod.GET,RequestMethod.POST})
    public String login(HttpServletRequest req,HttpServletResponse resp){
        String method = req.getMethod();
        String message = (String)req.getAttribute("message");
        //logger.debug(">>>>> to login,method={},message={}",method,message);
        if(StringUtils.equalsIgnoreCase("post",method) && StringUtils.isBlank(message)){
            return doLogin(req,resp);
        }else{
            return "login";
        }
    }

    public String doLogin(HttpServletRequest req,HttpServletResponse resp){
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //logger.debug(">>>>> do login,username={}",username);
        UsernamePasswordToken token = new UsernamePasswordToken(username,password.toCharArray());
        String message = "";
        try{
            SecurityUtils.getSubject().logout();
            Subject userSubject = SecurityUtils.getSubject();
            System.out.println(userSubject.getClass());
            userSubject.login(token);
            //必须执行一次，才能执行授权信息查询
            userSubject.hasRole("r");
            /*auths.getRoles().forEach(r ->{
                System.out.println("role ==== "+r);
            });*/
            /*ServletRequest request = ((WebDelegatingSubject)SecurityUtils.getSubject()).getServletRequest();
            HttpSession httpSession = ((HttpServletRequest)request).getSession();
            httpSession.setAttribute("roles",auths.getRoles());
            httpSession.setAttribute("perms",auths.getStringPermissions());*/
            return "redirect:/index";
        }catch (ExcessiveAttemptsException e) {
            message = "失败次数过多,请等待一段时间后重试！";
        } catch (LockedAccountException e) {
            message = "帐号已被锁定！";
        } catch (DisabledAccountException e) {
            message = "帐号信息不全或者已被禁用！";
        } catch (ExpiredCredentialsException e) {
            message = "帐号已被禁用或过期！";
        }  catch (UnauthorizedException e) {
            message = "您没有得到相应的授权！";
        }  catch (AuthenticationException e){
            message = "用户名或者密码错误！";
        }
        logger.error(">>>>> 登录失败：{}",message);
        req.setAttribute("message",message);
        req.setAttribute("username",username);
        return "login";
    }

    @RequestMapping(value = "/logout")
    public String logout(){
        SecurityUtils.getSubject().logout();
        return "login";
    }

    @RequestMapping(value = {"/index","/"})
    public ModelAndView index(HttpSession session){
        ModelAndView mav = new ModelAndView("index");
        if(ConstantData.securityEnable){
            String name = SecurityContextHolder.getContext().getAuthentication().getName();
            List<String> roles = new ArrayList<>();
            SecurityContextHolder.getContext().getAuthentication().getAuthorities().forEach(g ->{
                System.out.println("auth >> "+g.getAuthority());
                roles.add(g.getAuthority());
            });
            session.setAttribute("roles",roles);
            logger.debug(">>>>> the login user is {}",name);
        }else{
            /*String username = (String)SecurityUtils.getSubject().getPrincipal();
            System.out.println("from subject,"+username);
            Collection<String> roles = (Collection<String>)session.getAttribute("roles");
            if(roles != null){
                roles.forEach(r ->{
                    System.out.println("from session ,role = " + r);
                });
            }*/
            AuthorizationInfo auths = myShiroRealm.getAuthorizationCache().get(SecurityUtils.getSubject().getPrincipals());
            ServletRequest request = ((WebDelegatingSubject)SecurityUtils.getSubject()).getServletRequest();
            HttpSession httpSession = ((HttpServletRequest)request).getSession();
            httpSession.setAttribute("user",SecurityUtils.getSubject().getPrincipal());
            List<Menu> menus = null;
            if(auths != null){
                httpSession.setAttribute("roles",auths.getRoles());
                httpSession.setAttribute("perms",auths.getStringPermissions());
                listMenusFromPerms(auths.getStringPermissions());
            }
            if(CollectionUtils.isEmpty(menus) && StringUtils.equalsIgnoreCase("dev",ConstantData.activeProfile)){
                logger.debug("----- list the test menu data for dev -----");
                menus = TestData.menuData();
            }
            mav.addObject("menus", menus);
        }
        return mav;
    }

    private List<Menu> listMenusFromPerms(Collection<String> perms){
        return null;
    }

    /**
     * 刷新验证码
     * @param resp
     */
    @RequestMapping("/refreshCode")
    public void refreshCode(HttpServletRequest req,HttpServletResponse resp){
        resp.setDateHeader("Expires", 0);
        resp.setHeader("Cache-Control",
                "no-store, no-cache, must-revalidate");
        resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
        resp.setHeader("Pragma", "no-cache");
        resp.setContentType("image/jpeg");

        String sessionId = req.getSession(true).getId();
        String checkCode = captchaProducer.createText();
        //logger.debug(">>>>>> the generated checkcode is {},sessionId = {}",checkCode,sessionId);
        CommonUtils.cacheCheckCode(sessionId,checkCode);

        BufferedImage codeImg = captchaProducer.createImage(checkCode);
        OutputStream os = null;
        try {
            os =resp.getOutputStream();
            ImageIO.write(codeImg,"jpg",os);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(os != null){
                try {
                    os.flush();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * <h2>错误信息</h2>
     * <p>
     *     <h4>HTTP错误</h4>
     *     <ul>
     *         <li>401:未授权</li><li>403:禁止访问</li><li>404:资源不存在</li><li>500:服务器错误</li>
     *     </ul>
     * </p>
     * <p>
     *     <h4>自定义错误码</h4>
     *     <ul>
     *         <li>1001:操作错误</li><li>1002:非法访问</li><li>1003:授权过期</li>
     *     </ul>
     * </p>
     *
     * @return
     */
    @RequestMapping("/error/{code}")
    public ModelAndView error(@PathVariable String code,HttpServletRequest req){
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("code",code);
        String message = req.getParameter("message");
        if(StringUtils.isBlank(message)){
            message = ConstantData.codeDescMap.containsKey(code) ?
                    ConstantData.codeDescMap.get(code) : "未知错误";
        }
        mav.addObject("message",message);
        String detail = req.getParameter("detail");
        if(StringUtils.isBlank(detail)){
            String detailId = req.getParameter("detailId");
            if(StringUtils.isNoneBlank(detailId)){
                //从数据库查询
                detail = "从数据库查询的错误详情";
            }
        }
        mav.addObject("detail",detail);
        return mav;
    }

    @RequestMapping(value = "/page/{page}")
    public String showPage(@PathVariable("page") String page,
                           HttpServletRequest req,HttpServletResponse resp){
        //resp.setHeader("X-Frame-Options","SAMEORIGIN");
        page = page.replaceAll("_","/");
        logger.info("..... the view page is {}",page);
        return page;
    }
}
